package com.blocks.controller;

import java.io.IOException;
import java.util.Iterator;

import com.blocks.ScriptBlocksApplication;
import com.jme3.asset.AssetManager;
import com.jme3.audio.AudioNode;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.PhysicsTickListener;
import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.bullet.collision.PhysicsCollisionListener;
import com.jme3.bullet.collision.PhysicsCollisionObject;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.objects.PhysicsGhostObject;
import com.jme3.bullet.objects.PhysicsRigidBody;
import com.jme3.effect.EmitterSphereShape;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh.Type;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;

import jme3test.bullet.BombControl;

public class BlockBombControl extends RigidBodyControl implements PhysicsCollisionListener, PhysicsTickListener {

	    private float explosionRadius = 10;
	    private PhysicsGhostObject ghostObject;
	    private Vector3f vector = new Vector3f();
	    private Vector3f vector2 = new Vector3f();
	    private float forceFactor = 10;
	    private ParticleEmitter effect;
	    private float fxTime = 0.5f;
	    private float curTime = -1.0f;
	    private long startTime = System.currentTimeMillis();
	    private AudioNode audioNode;

	    public BlockBombControl(CollisionShape shape, float mass) {
	        super(shape, mass);
	        createGhostObject();
	    }

	    public BlockBombControl(AssetManager manager, CollisionShape shape, float mass) {
	        super(shape, mass);
	        createGhostObject();
	        prepareEffect(manager);
	        prepareSound(manager);
	    }

	    public void setPhysicsSpace(PhysicsSpace space) {
	        super.setPhysicsSpace(space);
	        if (space != null) {
	            space.addCollisionListener(this);
	        }
	    }

	    private void prepareEffect(AssetManager assetManager) {
	        int COUNT_FACTOR = 1;
	        float COUNT_FACTOR_F = 1f;
	        effect = new ParticleEmitter("Flame", Type.Triangle, 32 * COUNT_FACTOR);
	        effect.setSelectRandomImage(true);
	        effect.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f, (float) (1f / COUNT_FACTOR_F)));
	        effect.setEndColor(new ColorRGBA(.4f, .22f, .12f, 0f));
	        effect.setStartSize(1.3f);
	        effect.setEndSize(2f);
	        effect.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f));
	        effect.setParticlesPerSec(0);
	        effect.setGravity(-5f);
	        effect.setLowLife(.4f);
	        effect.setHighLife(.5f);
	        effect.setInitialVelocity(new Vector3f(0, 7, 0));
	        effect.setVelocityVariation(1f);
	        effect.setImagesX(2);
	        effect.setImagesY(2);
	        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
	        mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));
	        effect.setMaterial(mat);
	        effect.setLocalScale(100);
	    }
		  private void playBang() {		    	 
				 ScriptBlocksApplication.getInstance().getAudioRenderer().playSource(audioNode); 
				 ScriptBlocksApplication.getInstance().getRootNode().getChildren().add(audioNode);
			    
			  }
		  private void prepareSound(AssetManager assetManager) {		    	 
				  audioNode = new AudioNode( null, assetManager, "Sounds/bird_splat.wav", false);
				  audioNode.setLooping(false);
				  audioNode.setPositional(true);
				  audioNode.setVolume(1.0f);
				
			  }

	    protected void createGhostObject() {
	        ghostObject = new PhysicsGhostObject(new SphereCollisionShape(explosionRadius));
	    }

	    public void collision(PhysicsCollisionEvent event) {
	    	if(checkTime()){
		        if (space == null) {
		            return;
		        }
		        if (event.getObjectA() == this || event.getObjectB() == this) {
		            space.add(ghostObject);
		            ghostObject.setPhysicsLocation(getPhysicsLocation(vector));
		            space.addTickListener(this);
		            if (effect != null && spatial.getParent()!=null) {
		                curTime = 0;
		                effect.setLocalTranslation(spatial.getLocalTranslation());
		                spatial.getParent().attachChild(effect);
		                effect.emitAllParticles();
		                this.playBang();
		            }
		            space.remove(this);
		            spatial.removeFromParent();
		            //TODO Disable Sound
		        }
	    	}
	    }



		public void prePhysicsTick(PhysicsSpace space, float f) {
			if(checkTime()){
				space.removeCollisionListener(this);
			}
	    }

	    public void physicsTick(PhysicsSpace space, float f) {
	    	if(checkTime()){
	        //get all overlapping objects and apply impulse to them
	        for (Iterator<PhysicsCollisionObject> it = ghostObject.getOverlappingObjects().iterator(); it.hasNext();) {
	            PhysicsCollisionObject physicsCollisionObject = it.next();
	            if (physicsCollisionObject instanceof PhysicsRigidBody) {
	                PhysicsRigidBody rBody = (PhysicsRigidBody) physicsCollisionObject;
	                rBody.getPhysicsLocation(vector2);
	                vector2.subtractLocal(vector);
	                float force = explosionRadius - vector2.length();
	                force *= forceFactor;
	                vector2.normalizeLocal();
	                vector2.multLocal(force);
	                ((PhysicsRigidBody) physicsCollisionObject).applyImpulse(vector2, Vector3f.ZERO);
	            }
	        }
	        space.removeTickListener(this);
	        space.remove(ghostObject);
	    	}
	    }

	    @Override
	    public void update(float tpf) {
	        super.update(tpf);
	        if (enabled && curTime >= 0) {
	            curTime+=tpf;
	            if(curTime>fxTime){
	                curTime=-1;
	                effect.removeFromParent();
	            }
	        }
	    }

	    /**
	     * @return the explosionRadius
	     */
	    public float getExplosionRadius() {
	        return explosionRadius;
	    }

	    /**
	     * @param explosionRadius the explosionRadius to set
	     */
	    public void setExplosionRadius(float explosionRadius) {
	        this.explosionRadius = explosionRadius;
	        createGhostObject();
	    }

	    @Override
	    public void read(JmeImporter im) throws IOException {
	        throw new UnsupportedOperationException("Reading not supported.");
	    }

	    @Override
	    public void write(JmeExporter ex) throws IOException {
	        throw new UnsupportedOperationException("Saving not supported.");
	    }

	    private boolean checkTime() {
			if(System.currentTimeMillis()-startTime > 2000){
				return true;
			}
			return false;
		}
	

}
